package middleware

import (
	"bytes"
	"errors"
	commonError "gin_http/utils/common/error"
	"gin_http/utils/common/response"
	"gin_http/utils/logger"
	"io"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"go.uber.org/zap"
)

func GlobalErrorHandler() gin.HandlerFunc {
	return func(c *gin.Context) {
		requestId := uuid.New().String()
		c.Set(logger.RequestIDKey, requestId)

		// 创建带请求ID和基本信息的结构化logger
		stuctLogger := logger.WithRequestID(c, requestId).With(
			zap.String("method", c.Request.Method),
			zap.String("path", c.Request.RequestURI),
			zap.String("client_ip", c.ClientIP()),
		)
		logger.SetLoggerToContext(c, stuctLogger)

		start := time.Now()

		var requestBody []byte
		if c.Request.Method == http.MethodPut || c.Request.Method == http.MethodDelete || c.Request.Method == http.MethodPost {
			var err error
			requestBody, err = io.ReadAll(c.Request.Body)
			if err != nil {
				c.JSON(http.StatusInternalServerError, response.ApiResponse{Code: commonError.CodeInternalError, Message: "Failed to read request body", Data: nil, TimeStamp: time.Now().Unix(), RequestId: requestId})
				stuctLogger.Error("Failed to read request body", zap.Error(err))
				c.Abort()
				return
			}
			c.Request.Body = io.NopCloser(bytes.NewReader(requestBody))
		}

		c.Next()

		duration := time.Since(start)

		// 使用结构化日志记录请求信息
		if len(c.Errors) > 0 {
			// 在处理错误时记录日志
		} else {
			// 请求成功时记录日志
			stuctLogger.Info("request_success",
				zap.Int("status_code", c.Writer.Status()),
				zap.Duration("duration", duration),
				zap.Int("request_size", len(requestBody)),
			)
		}

		if len(c.Errors) > 0 {
			err := c.Errors.Last()

			var customErr *commonError.Error
			if errors.As(err.Err, &customErr) {
				c.JSON(http.StatusOK, response.ApiResponse{
					Code:      customErr.Code,
					Message:   customErr.Message,
					Data:      nil,
					TimeStamp: time.Now().Unix(),
					RequestId: requestId,
				})
				stuctLogger.Warn("request_error",
					zap.Int("error_code", customErr.Code),
					zap.String("error_message", customErr.Message),
					zap.String("error_file", customErr.File),
					zap.Int("error_line", customErr.Line),
					zap.Duration("duration", duration),
				)

			} else {
				c.JSON(http.StatusInternalServerError, response.ApiResponse{
					Code:      commonError.CodeInternalError,
					Message:   "服务异常，请稍候充实",
					Data:      nil,
					TimeStamp: time.Now().Unix(),
					RequestId: requestId,
				})
				stuctLogger.Error("request_panic",
					zap.String("error_message", err.Err.Error()),
					zap.Duration("duration", duration),
				)
			}
		}
	}
}
